package com.example.microuser.user.service.impl;


import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.common.core.common.JwtUtils;
import com.example.common.core.entity.User;
import com.example.common.core.ex.BusinessException;
import com.example.common.core.utils.TokenUtils;
import com.example.common.core.utils.UserUtils;
import com.example.common.neo4j.utils.Neo4jUtils;
import com.example.common.redis.utils.RedisKeyConstant;
import com.example.common.redis.utils.RedisUtils;
import com.example.common.neo4j.node.UserNode;
import com.example.microuser.user.mapper.UserMapper;
import com.example.microuser.user.pojo.DTO.LoginParam;
import com.example.microuser.user.pojo.VO.MyVO;
import com.example.microuser.user.service.UserService;
import com.example.microuser.user.pojo.DTO.UserDTO;
import io.jsonwebtoken.Claims;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private TokenUtils tokenUtils;
    @Autowired
    private Neo4jUtils neo4jUtils; // Neo4j图数据库工具类，用于操作用户关系图谱

    @Autowired
    private ThreadPoolExecutor threadPool; // 线程池，用于异步执行Neo4j操作

    /**
     * 注册
     * 1) 对参数进行校验
     * 1.1) 校验参数是否为空
     * 1.2) 校验用户名和手机号是否重复
     * 2) 验证码
     * 3) 是否有邀请码
     *
     * @param userDTO
     */
    @Override
    public void register(UserDTO userDTO) {
        // 手机号是null或者是"",或者 长度不等于11 -->格式不正确
        // if (!StringUtils.hasText(userDTO.getPhone()) || userDTO.getPhone().length() != 11) {
        //     throw new BusinessException("手机号格式不正确");
        // }

        // 判断密码
        // if (!StringUtils.hasText(userDTO.getPassword())) {
        //     throw new BusinessException("密码不能为空!");
        // }

        // 用户名重复性校验...
        // User u = userMapper.selectOne(
        //         Wrappers.lambdaQuery(User.class).
        //                 eq(User::getUsername, userDTO.getUsername()));
        // if (!ObjectUtils.isEmpty(u)) {
        //     // 不为空,即存在该用户名,不让注册
        //     throw new BusinessException("用户名已存在!");
        // }

        LambdaQueryWrapper<User> lambdaQuery = Wrappers.lambdaQuery(User.class);
        lambdaQuery.eq(User::getUsername, userDTO.getUsername());
        boolean exists = userMapper.exists(lambdaQuery);// 有该用户名的对象,返回就是true
        if (exists) {
            // 不为空,即存在该用户名,不让注册
            throw new BusinessException("用户名已存在!");
        }

        // 验证码
        if (!StringUtils.hasText(userDTO.getCode())) {
            throw new BusinessException("验证码不能为空!");
        }
        // 不为空,就从redis取出
        String code = redisUtils.getCacheObject(RedisKeyConstant.PHONE_CODE_KEY + userDTO.getPhone());
        if (!StringUtils.hasText(code)) {
            throw new BusinessException("验证码过期!");
        }
        if (!code.equals(userDTO.getCode())) {
            throw new BusinessException("验证码错误!");
        }

        /**
         * 注册时,携带一个别人给他的邀请码
         * 根据邀请码,查询邀请人的id
         * 给pid赋值
         * 再重新生成新的邀请码赋值给注册人(确保不能重复)
         */
        User user = new User();
        BeanUtils.copyProperties(userDTO, user);
        User parentUser;
        if (StringUtils.hasText(userDTO.getInviteCode())) { // 有邀请码
            parentUser = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getInviteCode, userDTO.getInviteCode()));
            // 根据邀请码查不出人
            if (ObjectUtils.isEmpty(parentUser)) {
                throw new BusinessException("邀请码有误!");
            }

            Integer pid = parentUser.getId();
            user.setPid(pid);
        } else {
            parentUser = null;
        }

        // 产生6位随机数
        String newInviteCode = RandomUtil.randomString(6);
        user.setInviteCode(newInviteCode);
        userMapper.insert(user);


        // 注册后异步执行Neo4j操作（线程池优化）
        threadPool.execute(()->{
            try {
                Thread.sleep(30*1000); // 模拟延迟（实际可删除）
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 1. 构建当前注册用户的Neo4j节点
            UserNode userNode = new UserNode();
            userNode.setId(user.getId());
            userNode.setName(user.getUsername());

            // 2. 若有邀请码，构建「邀请人-被邀请人」的关系；若无，仅添加当前用户节点
            if (StringUtils.hasText(userDTO.getInviteCode())) {
                UserNode parentNode = new UserNode();
                parentNode.setId(parentUser.getId());
                parentNode.setName(parentUser.getUsername());
                neo4jUtils.addNode(parentNode, userNode); // 创建邀请关系（父节点→子节点）
            } else {
                neo4jUtils.addNode(userNode); // 仅创建当前用户节点
            }
        });
    }

    /**
     * 发送手机验证码
     * @param phone
     * @return
     */
    @Override
    public String sendCode(String phone) {
        // 只能模拟发送验证码
        // 手机号是null或者是"",或者 长度不等于11 -->格式不正确
        if (!StringUtils.hasText(phone) || phone.length() != 11) {
            throw new BusinessException("手机号格式不正确");
        }

        // 模拟发送验证码
        String code = RandomUtil.randomNumbers(4);
        // 因为是模拟验证码,无法真的发送到手机,所以此处是输出
        System.out.println("手机验证码 = " + code);

        // 将验证码存储到redis,设置过期时间为5分钟
        // key: phone:code:13800000000
        redisUtils.setCacheObject(RedisKeyConstant.PHONE_CODE_KEY +phone,code,30, TimeUnit.SECONDS);

        return code;
    }

    /**
     * 登录
     * @param loginParam
     * @return
     */
    @Override
    public String login(LoginParam loginParam) {
        // 校验已经通过@Validated 实现

        // 根据用户名查询
        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUsername, loginParam.getUsername()));

        if (ObjectUtils.isEmpty(user)) {
            throw new BusinessException("用户名不存在!");
        }
        // 判断密码
        if (!user.getPassword().equals(loginParam.getPassword())) {
            throw new BusinessException("密码不正确!");
        }

        // 创建令牌
        HashMap<String, Object> map = new HashMap<>();
        map.put("uid",user.getId());
        String token = jwtUtils.createToken(map);

        return token;
    }

    /**
     * 查询用户信息
     * @return
     */
    @Override
    public MyVO getInfo() {
        // 获取当前请求对象,解析令牌,获取token,从而获取其中数据
        // ServletRequestAttributes requestAttributes =(ServletRequestAttributes)  RequestContextHolder.getRequestAttributes();
        // HttpServletRequest request = requestAttributes.getRequest();
        // String token = request.getHeader("token");
        // Claims claims = jwtUtils.parseToken(token);
        // Integer uid = (Integer) claims.get("uid");

        // Integer uid = tokenUtils.getUserIdFromToken();

        Integer uid = UserUtils.getUid();

        User user = userMapper.selectById(uid);

        MyVO myVO = new MyVO();
        BeanUtils.copyProperties(user,myVO);
        // 余额,积分,签到状态是0
        myVO.setPoint(0);
        myVO.setBalance(0);
        myVO.setSignFlag(0);

        return myVO;
    }

    @Override
    public void updateById(User user) {
        userMapper.updateById(user);
    }


}
